from datetime import timedelta

from odoo import fields, api, models
from odoo.exceptions import UserError
from ...functions.rp_finance_related_func import RpFinanceRelatedFunc
from functional import seq
from odoo.addons.basic_configuration.functions.logger import log

PAY_METHOD = [('stripe', 'Stripe支付'), ('balance', '余额支付'), ('union', '组合支付')]
PAYMENT_STATE = [('drift', '草稿'), ('not_pay', '未支付'), ('pay', '已支付'), ('error', '错误'), ('refunded', '已退款'), ('invoiced', '已开票')]
PAYMENT_LINE_TYPE = [('mail_route', '邮路'), ('fulfillment', '头尾程'), ('value_added', '增值服务')]


class RpPayment(models.Model):
    _name = 'rp.payment'
    _description = '支付单'
    _rec_name = 'code'
    _order = 'time_create desc'
    _sql_constraints = [('related_fields_uniq', 'unique(advance_document_id)', '相关记录必须唯一！')]

    code = fields.Char(string='编码', readonly=True)
    advance_document_id = fields.Many2one(string='前置单据', comodel_name='rp.related.model')
    advanced_document_model_name = fields.Char(string='前置单据模型名称', related='advance_document_id.field_name_id.name', help='方便筛选，无业务逻辑需求')
    customer_id = fields.Many2one(string='客户记录', comodel_name='rp.related.model')
    pay_method = fields.Selection(string='支付方式', selection=PAY_METHOD)
    total_balance_price = fields.Float(string='余额支付总金额')
    total_stripe_price = fields.Float(string='Stripe支付总金额')
    rp_payment_line_ids = fields.One2many(string='支付明细', comodel_name='rp.payment.line', inverse_name='order_payment_id')
    state = fields.Selection(string='状态', selection=PAYMENT_STATE)
    invoiced_tag = fields.Boolean(string='已开票', compute='depends_on_state', store=True)
    pay_url = fields.Char(string='支付链接')
    # 时间字段
    time_create = fields.Datetime(string='创建时间', default=lambda r: fields.Datetime.now())
    expired_time = fields.Datetime(string='过期时间', compute='depends_on_time_create', store=True)
    success_paytime = fields.Datetime(string='支付成功时间')
    remaining_second = fields.Integer(string='剩余秒数', help='由自动任务进行计算')
    active = fields.Boolean(string='有效', default=True)

    """
    Common Function
    """

    def gene_invoice(self, advanced_records_ids):
        """
        Params:
        -advanced_records_ids:前置单据
        生成发票
        """
        rp_payment_ids = RpFinanceRelatedFunc(self.env).geneate_invoice(seq(advanced_records_ids).map(lambda r: r.id).to_list(), advanced_records_ids[0]._name)
        # 修改状态
        for rc in rp_payment_ids:
            rc.write({'state': 'invoiced'})
            advance_id = self.env[rc.advance_document_id.field_name_id.model].search([('id', '=', rc.advance_document_id.field_record_id)])
            advance_id.write({'invoice_flag': True})

    """
    Native
    """

    @api.model_create_multi
    def create(self, vals_list):
        for vals in vals_list:
            vals['code'] = self.env['ir.sequence'].next_by_code('rp.payment') or '/'
        return super(RpPayment, self).create(vals_list)

    """
    Depends
    """

    @api.depends('state')
    def depends_on_state(self):
        for record in self:
            if record.state == 'invoiced':
                record.write({'invoiced_tag': True})
            else:
                record.write({'invoiced_tag': False})

    @api.depends('time_create')
    def depends_on_time_create(self):
        for record in self:
            expired_amount = int(self.env['ir.config_parameter'].get_param('ship_order.expired_time')) if self.env['ir.config_parameter'].get_param('ship_order.expired_time') else 30
            record.write({'expired_time': record.time_create + timedelta(minutes=expired_amount)})

    """
    Ir Cron
    """

    def compute_expired_time_and_behind_process(self):
        """
        计算过期时间
        """
        # 所有支付单计算过期时间
        rp_payment_ids = self.env['rp.payment'].with_context(active_test=False).search([])
        for record in rp_payment_ids:
            if record.state not in ['pay', 'error', 'invoiced', 'refunded']:
                if record.expired_time:
                    time_difference = record.expired_time - fields.datetime.now()
                    seconds = time_difference.total_seconds() if time_difference.total_seconds() >= 0 else 0
                    record.write({'remaining_second': int(seconds)})
                    if seconds == 0:
                        # 逻辑删除支付单和订单
                        record.write({'active': False})
                        advanced_document_id = record.env[record.advance_document_id.field_name_id.model].search([('id', '=', record.advance_document_id.field_record_id)])
                        advanced_document_id.write({'active': False})

    """
    Button Function
    """

    def forward_to_pay(self):
        if self.pay_url:
            return {
                'type': 'ir.actions.act_url',
                'url': self.pay_url,
                'target': 'self'
            }
        else:
            raise UserError('配置错误!')

    def upstream_the_origin_for_advance_document(self):
        """
        查看前置单据的按钮函数
        """
        log('触发了前置单据上查按钮！')
        if self.advance_document_id:
            result = RpFinanceRelatedFunc(self.env).forward_to_upstream_form(self.advance_document_id)
            log('返回视图成功！')
            return result
        else:
            log('没有来源，无法打开视图！')
            raise UserError("没有来源，无法打开视图")

    def upstream_the_origin_for_customer(self):
        """
        查看客户记录的按钮函数
        """
        log('触发了客户记录上查按钮！')
        if self.advance_document_id:
            result = RpFinanceRelatedFunc(self.env).forward_to_upstream_form(self.customer_id)
            log('返回视图成功！')
            return result
        else:
            log('没有来源，无法打开视图！')
            raise UserError("没有来源，无法打开视图")

    @api.model
    def action_aggregate_payment(self, active_ids):
        """
        聚合并校验订单数据
        Params:
        -active_ids:活跃的记录ID
        """
        rp_payment_ids = self.env['rp.payment'].search([('id', '=', active_ids)])
        # NOTE 数据校验
        # 前置单据的类型需要一致
        advanced_document_model = rp_payment_ids.mapped(lambda r: r.advance_document_id.field_name_id.model)
        if len(set(advanced_document_model)) != 1:
            raise Exception('您选择的支付单对应的前置单据类型不一致，请重新选择！')
        # 前置单据未完成或已开票错误提示
        advance_ids = seq(rp_payment_ids).map(lambda r: r.advance_document_id.field_record_id).to_list()
        advanced_document_ids = self.env[advanced_document_model[0]].search([('id', 'in', advance_ids)])
        if len(advanced_document_ids.filtered(lambda r: r.state != 'done')) != 0:
            raise Exception('您选择的支付单对应的前置单据未完成或已开票，请重新选择！')
        # 不是一个用户的选择错误
        customer_id = advanced_document_ids.mapped(lambda r: r.customer_id.id)
        if len(set(customer_id)) != 1:
            raise Exception('您选择的订单不是同一个客户，请重新选择！')
        action = self.env.ref('rp_finance_management.rp_invoice_address_tran_view_action')
        view_form = self.env.ref('rp_finance_management.rp_invoice_address_tran_form_view', False)
        result = action.read()[0]
        result['views'] = [(view_form.id, 'form')]
        result['name'] = '发票地址填充向导'
        result['views'] = [(view_form.id, 'form')]
        result['context'] = {'active_ids': advanced_document_ids.ids, 'model_id': rp_payment_ids[0].advance_document_id.field_name_id.id}
        result['target'] = 'new'
        return result


class RpShipOrderPayment(models.Model):
    _name = 'rp.ship.order.payment'
    _description = '保持源系统一致(重新安装系统可删除)'
    inherit = ['rp.payment']


class RpPaymentLine(models.Model):
    _name = 'rp.payment.line'
    _description = '支付明细'

    order_payment_id = fields.Many2one(string='支付单', comodel_name='rp.payment')
    pay_method = fields.Selection(string='支付方式', selection=PAY_METHOD)
    stripe_price = fields.Float(string='Stripe支付金额', digits=(12, 3))
    balance_price = fields.Float(string='余额支付金额', digits=(12, 3))
    currency_id = fields.Many2one(string='金额单位', comodel_name='res.currency', default=lambda self: self.env.company.currency_id)
    tax_price = fields.Float(string='税值')
    type = fields.Selection(string='类型', selection=PAYMENT_LINE_TYPE)
    description = fields.Char(string='描述')
    state = fields.Selection(string='状态', selection=PAYMENT_STATE, related='order_payment_id.state', store=True)


class OrderPaymentLine(models.Model):
    _name = 'order.payment.line'
    _description = '保持源系统一致(重新安装系统可删除)'
    inherit = ['rp.payment.line']
